package main

import (
	"fmt"
	"math/rand"
	"time"
)

// or函数接收多个channels，返回一个channel，
// 当任何一个输入channel接收到值或关闭时，返回的channel会收到通知
func or(channels ...<-chan interface{}) <-chan interface{} {
	// 特殊情况处理
	switch len(channels) {
	case 0:
		// 没有输入channels，返回一个已关闭的channel
		c := make(chan interface{})
		close(c)
		return c
	case 1:
		// 只有一个输入channel，直接返回它
		return channels[0]
	}

	// 创建输出channel
	orDone := make(chan interface{})

	// 启动一个goroutine来处理多个channel
	go func() {
		defer close(orDone)

		// 创建一个递归的使用select的函数
		// 这允许我们动态地处理任意数量的channels
		var cases []<-chan interface{}
		cases = append(cases, channels...)

		// 再启动一个goroutine来递归处理剩余的channels
		// 这种递归方式可以处理任意数量的channels
		orChild := or(cases[2:]...)

		// 等待任何一个channel收到信号
		select {
		case <-cases[0]:
			// 第一个channel收到信号
		case <-cases[1]:
			// 第二个channel收到信号
		case <-orChild:
			// 剩余的channels中的一个收到信号
		}
	}()

	return orDone
}

// 模拟一个会在随机时间后发送信号的过程
func worker(name string, delay time.Duration) <-chan interface{} {
	c := make(chan interface{})
	go func() {
		defer close(c)
		fmt.Printf("%s: 开始工作，预计需要 %v\n", name, delay)
		time.Sleep(delay)
		fmt.Printf("%s: 工作完成!\n", name)
	}()
	return c
}

func main() {
	// 设置随机数种子
	rand.Seed(time.Now().UnixNano())

	// 开始时间
	start := time.Now()

	fmt.Println("等待多个工作完成中的任意一个...")

	// 创建几个需要不同时间完成的工作
	work1 := worker("工作1", time.Duration(rand.Intn(3)+1)*time.Second)
	work2 := worker("工作2", time.Duration(rand.Intn(3)+1)*time.Second)
	work3 := worker("工作3", time.Duration(rand.Intn(3)+1)*time.Second)
	work4 := worker("工作4", time.Duration(rand.Intn(3)+1)*time.Second)

	// 使用or-channel模式等待任何一个工作完成
	<-or(work1, work2, work3, work4)

	// 等待一会儿
	time.Sleep(time.Second)
	fmt.Printf("至少一个工作已完成! 总共耗时: %v\n", time.Since(start))

	// 展示or-channel在超时情况下的使用
	fmt.Println("演示带超时的or-channel:")

	timeout := make(chan interface{})
	go func() {
		time.Sleep(2 * time.Second)
		close(timeout)
		fmt.Println("超时触发!")
	}()

	work5 := worker("慢工作", 5*time.Second)

	// 等待工作完成或超时
	select {
	case <-work5:
		fmt.Println("慢工作完成")
	case <-timeout:
		fmt.Println("等待超时，取消操作")
	}

	// 演示一个实际应用场景：第一个响应胜出
	fmt.Println("从多个数据源获取数据，第一个响应的胜出")

	// 模拟从不同数据源获取数据
	source1 := fetchData("数据源1", 2*time.Second)
	source2 := fetchData("数据源2", 1*time.Second)
	source3 := fetchData("数据源3", 3*time.Second)

	// 等待第一个数据源响应
	<-or(source1, source2, source3)
	fmt.Println("已获得第一个响应，可以开始处理数据")
}

// 模拟从数据源获取数据
func fetchData(sourceName string, delay time.Duration) <-chan interface{} {
	c := make(chan interface{})
	go func() {
		defer close(c)
		fmt.Printf("正在从 %s 获取数据...\n", sourceName)
		time.Sleep(delay)
		fmt.Printf("%s 返回数据", sourceName)
	}()
	return c
}
